#pragma once
/*
 * pipe session class as anet ISession.
 */

#include <string>
#include "pipe_define.h"
#include "share_ptr_session.hpp"
#include "pipe.h"
#include "pipe_enum.h"
#include "time_wheel.h"

// declare anet CClient.
namespace anet {
	namespace tcp {
		class CClient;
	}
}

namespace anet {
	namespace pipe {
		class IPipeMsgHandler;
		class CPipeSession;
		using sharePtrSession = anet::tcp::CSharePtrSession<CPipeSession>;

		// pipe session.
		class CPipeSession : public IPipe {
		public:
			CPipeSession();
			virtual ~CPipeSession();

			// timer id and timer time.
			enum class eConst : uint64 {
				// beat heart check timer const.
				pipe_beat_heart_check_timer_id = 0,
				pipe_beat_heart_check_timer_time = 10 * 1000,

				// beat heart send timer const
				pipe_beat_heart_send_timer_id = 1,
				pipe_beat_heart_send_timer_time = 5 * 1000,

				pipe_check_state_timer_id = 2,
				pipe_check_state_timer_time = 20*1000,
			};

		public:
			// IPipe interface for user.
			virtual void SetMsgHandler(IPipeMsgHandler* msgHandler) override;
			virtual void Send(const char* msg, int len) override;
			virtual unsigned int GetPipeId() const override;
			virtual SPipeId GetPipeInfo() const override;
			virtual unsigned int GetRemotePipeId() const override;
			virtual SPipeId GetRemotePipeInfo() const override;
			virtual IPipeMsgHandler* GetMsgHandler() override;
			virtual void Close() override;

		public:
			void SetRemoteId(uint32 id);
			void SetToken(const std::string& token);
			void SetMode(ePipeMode mode);
			ePipeMode GetMode() const { return m_mode; }
			void SetClient(anet::tcp::CClient* client);
			
		public:
			// template function interface.
			static CPipeSession* Create();
			void SetSession(sharePtrSession* pSession);
			void OnMessage(const char* msg, int len);
			void OnConnected();
			void OnTerminate();
			void OnRelease();

		protected:
			// pipe sending message.
			void sendConnectReq();
			void sendConnectAck();
			void sendBeatHeart();
			void startTimerToSendBeatHeart();
			void startTimerToCheckBeatHeart();
			void reconnect();
			void checkStatus();

		private:
			// it is valid for connector mode 
			// which represent the remote server's information.
			int64 m_lastBeatHeart{ 0 };
			uint32 m_remoteId{ 0 };
			std::string m_token{ "" };

			// share pointer Session pointer(template object).
			sharePtrSession *m_session{ nullptr };

			// pipe mode.
			ePipeMode m_mode{ ePipeMode::pipe_mode_listener };

			// pipe state
			ePipeState m_state{ ePipeState::pipe_session_state_invalid };

			// pipe message handler callback(from user).
			IPipeMsgHandler* m_pipeHandler{ nullptr };

			// timer register.
			STimeWheelSpace::CTimerRegister m_timer;

			// client pointer(for client reconnect).
			anet::tcp::CClient* m_client{ nullptr };

			// beat heart time.
			static const int gBeatHearTime = 10 * 1000;
		};
	}
}